﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;

namespace ClassFolio.Model
{
    public class User : IDataErrorInfo
	{
        #region Создание пользователя

        /// <summary>
        /// Статический метод класса для создания нового пользователя в системе
        /// </summary>
        /// <returns></returns>
        public static User CreateUser()
        {
            return new User();
        }

        /// <summary>
        /// По переданному идентификатору, создается экземпляр класса User.
        /// Если пользователь с заданным ID не существует в системе, возвращается null
        /// </summary>
        /// <param name="userId">Идентификатор пользователя в базе данных</param>
        /// <returns>Возвращается экземпляр объекта пользователя. Если пользователь с заданным ID 
        /// не найден, возвращается null</returns>
        public static User CreateUserById(int userId)
        {
            return new User(userId);
        }

        /// <summary>
        /// Защищиенный конструктор для создания пользователя и инициализации полей из базы данных
        /// </summary>
        /// <param name="id"></param>
        protected User(int id) 
        {
            this.ID = id;
            RefreshFromDb();
        }

        /// <summary>
        /// Защищиенный конструктор для создания "пустого" пользователя
        /// </summary>
        protected User() 
        {
            this.Name = "";
            this.Password = "";
            this.Patname = "";
            this.Surname = "";
            this.UserLogin = "";
        }
        
        #endregion //Создание пользователя

        #region Users properties

        /// <summary>
        /// Идентификатор пользователя в базе данных
        /// <remarks>Свойство только для чтения. Идентификатор созается базой данных в момент создания нового
        /// пользователя и не может быть впоследствии изменен</remarks>
        /// </summary>
        public int ID { get; private set; }

        /// <summary>
        /// Имя пользователя. 
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Отчество пользователя
        /// </summary>
        public string Patname { get; set; }

        /// <summary>
        /// Фамилия пользователя
        /// </summary>
        public string Surname { get; set; }

        /// <summary>
        /// Логин пользователя. 
        /// </summary>
        public string UserLogin { get; set; }

        /// <summary>
        /// Пароль пользователя 
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// Состояние активности пользователя
        /// </summary>
        public bool IsActive { get; set; }

        /// <summary>
        /// Набор прав в системе для пользователя
        /// </summary>
        public List<UsersAction> ActionList { get { return this._userAction; } }

        /// <summary>
        /// Список ролей, которые даны пользователю
        /// </summary>
        public List<int> RoleList { get { return this._roleIdList; } }

        /// <summary>
        /// Шлюз таблицы
        /// </summary>
        public static IUserGate UserGate { get; set; }

        /// <summary>
        /// Пользователь в настоящий момент присоединенный к системе
        /// </summary>
        /// <remarks>
        /// Значение свойству присваивается во время инициализации системы функцией 
        /// <see cref="LoginAs"/> класса <see cref="GeneFolio.AreaWork.AreaWork"/>
        /// </remarks> 
        public static User LogonUser { get; set; }

        #endregion

        #region IDataErrorInfo Members/ Validation

        string IDataErrorInfo.Error { get { return null; } }

        string IDataErrorInfo.this[string propertyName]
        {
            get { return this.GetValidationError(propertyName); }
        }
        
        /// <summary>
        /// Свойства класса для которых отрабатывается проверка на правильность ввода
        /// </summary>
        private readonly string[] ValidatedProperties = 
        { 
            "ID", 
            "Name", 
            "Patname",
            "Surname",
            "UserLogin"
        };

        private string GetValidationError(string propertyName)
        {
            if (Array.IndexOf(ValidatedProperties, propertyName) < 0)
                return null;

            string error = null;

            switch (propertyName)
            {
                case "ID":
                    error = this.ValidateID();
                    break;
                case "Name":
                    error = this.ValidateName();
                    break;
                case "Patname":
                    error = this.ValidatePatname();
                    break;
                case "Surname":
                    error = this.ValidateSurname();
                    break;
                case "UserLogin":
                    error = this.ValidateUserLogin();
                    break;
                default:
                    Debug.Fail("Unexpected property being validated on Customer: " + propertyName);
                    break;
            }

            return error;
        }

        /// <summary>
        /// Возвращает true, если объект не содержит ошибок
        /// </summary>
        public bool IsValid
        {
            get
            {
                foreach (string property in ValidatedProperties)
                    if (GetValidationError(property) != null)
                        return false;

                return true;
            }
        }

        private string ValidateID()
        {
            if (this.ID < 0)
            {
                return ValidErrors.User_Error_MissingID;
            }
            return null;
        }

        private string ValidateName()
        {
            if (Tools.IsStringMissing(this.Name) || this.Name.Trim().Length > 32)
            {
                return ValidErrors.User_Error_MissingName;
            }
            return null;
        }

        private string ValidatePatname()
        {
            if (Tools.IsStringMissing(this.Patname) || this.Patname.Trim().Length > 32)
            {
                return ValidErrors.User_Error_MissingPatname;
            }
            return null;
        }

        private string ValidateSurname()
        {
            if (Tools.IsStringMissing(this.Surname) || this.Surname.Trim().Length > 32)
            {
                return ValidErrors.User_Error_MissingSurname;
            }
            return null;
        }

        private string ValidateUserLogin()
        {
            if (Tools.IsStringMissing(this.UserLogin) || this.UserLogin.Trim().Length > 32)
            {
                return ValidErrors.User_Error_MissingUserLogin;
            }
            return null;
        }

        #endregion // IDataErrorInfo Members/ Validation

        #region Helper

        /// <summary>
        /// Обновление значений свойств класса, из базы данных
        /// </summary>
        public void RefreshFromDb()
        {
            UserGate.RefreshFromDb(this);
            this._userAction = UserGate.GetUsersAction(this.ID);
            this._roleIdList = UserGate.GetRoleList(this.ID);
        }

        #endregion // Helper

        #region Fields

        private List<UsersAction> _userAction;
        private List<int> _roleIdList;

        #endregion

        ///// <summary>
        ///// Проверяется наличие пользователя в системе.
        ///// </summary>
        ///// <param name="user">Экземпляр класса пользователя, наличие которого необходимо проверить</param>
        ///// <returns>Если пользователь в системе существует, возвращается значение true, если нет - false</returns>
        //public static bool UserExist(User user)
        //{
        //    return UserGate.UserExist(user.ID);
        //}


        ///// <summary>
        ///// Удаление существующего пользователя
        ///// </summary>
        ///// <param name="user">Экземпляр ползователя, которого необходимо удалить из системы</param>
        ///// <remarks>Метод не удаляет пользователя из базы данных, вместо этого пользователь помечается
        ///// как неактивный Status = 0</remarks>
        ///// <exception cref="EFolio">Исключение генерируется, если пользователь пытается удалить сам себя</exception>
        //public static void RemoveUser(User user)
        //{
        //    if (LogonUser.ID == user.ID) // Пользователь не может сам себя удалить
        //        throw new EFolio(0, MessageType.UserMessage, Messages.um_remove_someself, null);

        //    UserGate.RemoveUser(LogonUser.ID, user.ID);
        //}

        ///// <summary>
        ///// Метод вызвается для сохранения измененных значений свойств класса в базе данных
        ///// </summary>
        //public void ApplyToDb()
        //{
        //    UserGate.ApplyToDb(LogonUser.ID, this);
        //}
        


        //#endregion

        //#region Работа с ролями и разрешениями

        ///// <summary>
        ///// Пользователю назначается новай роль
        ///// </summary>
        ///// <param name="role">Экземпляр роли, назначаемой пользователю</param>
        //public void AssignRole(Role role)
        //{
        //    UserGate.AssignRole(LogonUser.ID, this.ID, role.ID);
        //    this._userAction = UserGate.GetUsersAction(this.ID);
        //    this._roleIdList = UserGate.GetRoleList(this.ID);
        //}
        
        ///// <summary>
        ///// Ранее назначеная пользователю роль - отнимается
        ///// </summary>
        ///// <param name="role">Экземпляр класса роли</param>
        //public void RemoveRole(Role role)
        //{
        //    UserGate.RemoveRole(LogonUser.ID, this.ID, role.ID);
        //    this._userAction = UserGate.GetUsersAction(this.ID);
        //    this._roleIdList = UserGate.GetRoleList(this.ID);
        //}

        ///// <summary>
        ///// Пользователю назначается индивидуальное разрешение на действия actionId
        ///// </summary>
        ///// <param name="actionId">Идентификатор действия</param>
        ///// <remarks>Идентификатор действия должен быть получен из файла установок Actions.settings</remarks>
        //public void AssignAction(int actionId)
        //{
        //    UserGate.AllowAction(LogonUser.ID, this.ID, actionId);
        //    this._userAction = UserGate.GetUsersAction(this.ID);
        //}
        
        ///// <summary>
        ///// Действие запрещается для пользователя.
        ///// </summary>
        ///// <param name="actionId">Идентификатор действия, которое запрещается пользователю</param>
        ///// <remarks>Идентификатор действия должен быть получен из файла установок Actions.settings</remarks>
        //public void BanAction(int actionId)
        //{
        //    UserGate.BanAction(LogonUser.ID, this.ID, actionId);
        //    this._userAction = UserGate.GetUsersAction(this.ID);
        //}
        
        ///// <summary>
        ///// Для пользователя снимаются явные ограничения или запрещения по данному действия. Доступ к 
        ///// действию определяется полностью настройками ролей, которым принадлежит пользователь
        ///// </summary>
        ///// <param name="actionId">Иденификатор действия</param>
        ///// <remarks>Идентификатор действия должен быть получен из файла установок Actions.settings</remarks>
        //public void RemoveAction(int actionId)
        //{
        //    UserGate.RemoveAction(LogonUser.ID, this.ID, actionId);
        //    this._userAction = UserGate.GetUsersAction(this.ID);
        //}
		
        ///// <summary>
        ///// Проверка наличия прав доступа на действие
        ///// </summary>
        ///// <param name="actionId">Идентфикатор действия</param>
        ///// <returns>Наличие разрешение на выбранное действие</returns>
        ///// <remarks>Идентификатор действия должен быть получен из файла установок Actions.settings</remarks>
        //public bool HaveAction(int actionId)
        //{
        //    if (this.ID == 1)
        //        return true;
        //    else
        //    {
        //        return _userAction.Count(i => i.ID == actionId) == 1; 
        //    }
        //}

        ///// <summary>
        ///// Проверка принадлежности роли пользователю
        ///// </summary>
        ///// <param name="roleId">Идентификатор проверяемой роли</param>
        ///// <returns>Возвращает true, если пользователю назначена роль roleId, false - если не назначена</returns>
        //public bool HaveRole(Role role)
        //{
        //    return this._roleIdList.Contains(role.ID);
        //}

        //#endregion

        //#region Выборки из базы данных
		
        ///// <summary>
        ///// Выборка из базы данных. Содержит поля ID, NAME, SURNAME
        ///// </summary>
        ///// <param name="swth">Экземпляр класса фильтра записей</param>
        ///// <returns>Выборка полученная из базы, в соответствии с примененным фильтром</returns>
        //public static Sequence GetSequence(SqlSwitch swth)
        //{
        //    return UserGate.GetSequence(swth);
        //}

        ///// <summary>
        ///// Выборка из базы данных для быстрого поиска
        ///// </summary>
        ///// <param name="swth">Экземпляр класса фильтра записей</param>
        ///// <param name="filter">Условия быстрого поиска</param>
        ///// <returns>Выборка полученная из базы, в соответствии с примененным фильтром и 
        ///// условием быстрого поиска</returns>
        //public static Sequence GetQuickFindSequence(SqlSwitch swth, string filter)
        //{
        //    return UserGate.GetQuickFindSequence(swth, filter);
        //}

        //#endregion

	}

    public interface IUserGate
    {
        // Работа с пользователем
        void RemoveUser(int activeUserId, int userId);
        bool UserExist(int userId);
        User ApplyToDb(int activeUserId, User user);
        void RefreshFromDb(User user);
        bool SetActive(int activeUserId, int userId, bool isActive);

        // Работа с ролями и разрешениями
        void AssignRole(int activeUserId, int userId, int roleId);
        void RemoveRole(int activeUserId, int userId, int roleId);
        void AllowAction(int activeUserId, int userId, int actionId);
        void BanAction(int activeUserId, int userId, int actionId);
        void RemoveAction(int activeUserId, int userId, int actionId);
		List<UsersAction> GetUsersAction(int userId);
		List<int> GetRoleList(int userId);

        // Работа с наборами данных
        Sequence GetSequence(SqlSwitch swth);
		Sequence GetQuickFindSequence(SqlSwitch swth, string filter);
	}

    /// <summary>
    /// Структура содержит идентификатор и наименование разрешенного пользователю действия 
    /// </summary>
    public struct UsersAction
	{
		public UsersAction(int id, string name)
		{
			this._id = id;
			this._name = name;
		}

        /// <summary>
        /// Идентификатор разрешенного пользователю действия
        /// </summary>
		public int ID { get { return this._id; } }
        
        /// <summary>
        /// Наименование разрешенного пользователю действия
        /// </summary>
		public string Name { get { return this._name; } }

		private int _id;
		private string _name;
	}
}
